package spring.cloud.tasks.executor.name_space.executor.task;

import spring.cloud.tasks.common.Threads;
import spring.cloud.tasks.executor.name_space.executor.task.task_item.Status;
import spring.cloud.tasks.executor.name_space.executor.task.task_item.TaskItemExecuteInfoService;
import spring.cloud.tasks.executor.name_space.executor.task.task_listener.task_statistics.TaskStatistics;
import spring.cloud.tasks.executor.name_space.executor.tasks_runtime_info.task_item_assign.TaskIdToTaskInstanceIdToTaskItemIndexListMapMap;
import spring.cloud.tasks.executor.name_space.executor.tasks_runtime_info.task_item_execute.*;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;

/**
 * 任务执行状态和结果信息搜集线程(collect task execute status and execute result thread)
 */
public class TaskStateMaintenanceThread extends Thread {
    private final TaskExecutor taskExecutor;
    protected TaskItemExecuteInfoService taskItemExecuteInfoService;

    public TaskStateMaintenanceThread(TaskExecutor taskExecutor) {
        this.taskExecutor = taskExecutor;
    }

    @Override
    public void run() {
        try {

            Lock lock = taskExecutor.lock;
            if (taskExecutor.lock.tryLock(10, TimeUnit.SECONDS)) {
                try {
                    stateMaintenance();
                } catch (Exception ex) {

                } finally {
                    //当获取锁成功时最后一定要记住finally去关闭锁
                    lock.unlock();   //释放锁
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 如果当前任务片不在进行分配 那么则不在续期。出现这种情况 那么其他的执行器可以覆盖。
     *
     * @throws Exception
     */
    private void stateMaintenance() throws Exception {

        TaskExecuteRuntimeContext taskExecuteRuntimeContext = TasksExecuteRuntimeContext.getTaskExecuteRuntimeContext(taskExecutor.getTaskId());
        for (String taskInstanceId : TaskExecuteRuntimeContext.taskInstanceIdToTaskInstanceExecuteRuntimeContextMap.keySet()) {
            TaskInstanceExecuteRuntimeContext TaskItemExecuteRuntimeContexts = taskExecuteRuntimeContext.getTaskInstanceExecuteRuntimeContext(taskInstanceId);
            for (Integer taskItemIndex : TaskInstanceExecuteRuntimeContext.taskItemIndexToTaskItemExecuteRuntimeContextsMap.keySet()) {
                TaskItemExecuteRuntimeContexts taskItemExecuteRuntimeContexts = TaskItemExecuteRuntimeContexts.getTaskItemExecuteRuntimeContexts(taskItemIndex);
                stateMaintenance(taskItemExecuteRuntimeContexts);
            }
        }
        for (String taskInstanceId : TaskExecuteRuntimeContext.taskInstanceIdToTaskInstanceExecuteRuntimeContextMap.keySet()) {
            TaskInstanceExecuteRuntimeContext TaskItemExecuteRuntimeContexts = taskExecuteRuntimeContext.getTaskInstanceExecuteRuntimeContext(taskInstanceId);
            for (Integer taskItemIndex : TaskInstanceExecuteRuntimeContext.taskItemIndexToTaskItemExecuteRuntimeContextsMap.keySet()) {
                TaskItemExecuteRuntimeContexts taskItemExecuteRuntimeContexts = TaskItemExecuteRuntimeContexts.getTaskItemExecuteRuntimeContexts(taskItemIndex);
                if (taskItemExecuteRuntimeContexts != null) {
                    TaskItemExecuteRuntimeContext taskItemExecuteRuntimeContext = taskItemExecuteRuntimeContexts.currentTaskItemExecuteRuntimeContext;
                    if (taskItemExecuteRuntimeContext != null && taskItemExecuteRuntimeContext.isFinished() && !taskItemExecuteRuntimeContext.isReported) {
                        taskItemExecuteRuntimeContext.isReported = true;
                        reportTaskItemExecuteRuntimeContext(taskItemExecuteRuntimeContext);
                    }

                }

            }
        }
    }

    private void stateMaintenance(TaskItemExecuteRuntimeContexts taskItemExecuteRuntimeContexts) {
        if (taskItemExecuteRuntimeContexts.currentTaskItemExecuteRuntimeContext == null) {
            return;
        } else {
            TaskItemExecuteRuntimeContext taskItemExecuteRuntimeContext = taskItemExecuteRuntimeContexts.currentTaskItemExecuteRuntimeContext;
            //尝试性看看是否需要续期,如果任务完成了肯定就不用续期
            if (taskItemExecuteRuntimeContext.isFinished()) {
                return;
            }
            if (taskItemExecuteRuntimeContext.needStop) {
                return;//一直for循环检查状态,用needStop = true进行检查
            }
            long nowDateTime = System.currentTimeMillis();
            // 1线程信息
            String threadName = taskItemExecuteRuntimeContext.getThreadName();
            Thread thread = Threads.getThreadByhreadName(threadName);
            if (thread == null) {
                //可能线程没有创建或者已经终止了
                if (nowDateTime - taskItemExecuteRuntimeContext.getBeginTime() >= 1000 * 60) {
                    taskItemExecuteRuntimeContext.setStatus(Status.EXCEPTION_END);
                    taskItemExecuteRuntimeContext.setMessage("线程已经不存在了");
                    return;
                } else {
                    return;//等待下次，在这不能进行设置为任务结束
                }
            }
            if (!thread.isAlive()) {
                Threads.sleep();//status fix 可能任务执行的代码真正处于修改状态中
                if (taskItemExecuteRuntimeContext.getStatus() == Status.RUNNING) {
                    taskItemExecuteRuntimeContext.setStatus(Status.EXCEPTION_END);
                    taskItemExecuteRuntimeContext.setMessage("线程处于非活跃状态 但是还存在");
                    return;
                } else {
                    return;
                }

            }
            //2如果任务分片分配给其他的执行器 那么就不用进行续期了
            TaskIdToTaskInstanceIdToTaskItemIndexListMapMap taskIdToTaskInstanceIdToTaskItemIndexListMapMap = taskExecutor.getTaskInitService().getTaskIdToTaskInstanceIdToTaskItemIndexListMapMap();
            boolean isAssigned = taskIdToTaskInstanceIdToTaskItemIndexListMapMap.isAssigned(taskItemExecuteRuntimeContext);
            if (!isAssigned) {
                taskItemExecuteRuntimeContext.needStop = true;
                taskItemExecuteRuntimeContext.needStopMessage = "任务分配给其他执行器了或者任务已经取消";
                return;
            }
            // 3进行续期信息(如果任务信息和线程信息都校验失败 那么就不用进行续期)
            Long initRenewalTime = taskItemExecuteRuntimeContext.getInitRenewalTime();
            Long maxRenewalTime = taskItemExecuteRuntimeContext.getMaxRenewalTime();
            if (initRenewalTime > nowDateTime) {
                //不需要进行处理
                return;
            }
            if (nowDateTime > maxRenewalTime) {
                //已经超过最大的续期时间了
                taskItemExecuteRuntimeContext.needStop = true;
                taskItemExecuteRuntimeContext.needStopMessage = "已经超过最大的续期时间了";
                return;
            }

            //基于当前的时间点进行续期 但是续期的时间不要超过max的续期时间。
            if (nowDateTime + taskItemExecuteRuntimeContext.getRenewalInterval() > taskItemExecuteRuntimeContext.getMaxRenewalTime()) {
                taskItemExecuteRuntimeContext.needStop = true;
                taskItemExecuteRuntimeContext.needStopMessage = "即将超过最大的续期时间了";
                return;//即使再活跃也不能再续期了
            }
            // 4任务执行信息的汇报检查
            Long lastTaskSelfReportTime = taskItemExecuteRuntimeContext.getLastTaskSelfReportTime();
            if (lastTaskSelfReportTime == taskItemExecuteRuntimeContext.getBeginTime()) {
                //才开始
                return;
            }
            if (nowDateTime - lastTaskSelfReportTime < 1000 * 60 * 2) {
                //主动通知状态管理任务还存存活
                TaskItemExecuteRenewalInfo taskItemExecuteRenewalInfo = new TaskItemExecuteRenewalInfo();
                taskItemExecuteRenewalInfo.setExecutorId(taskItemExecuteRuntimeContext.getExecutorId());
                taskItemExecuteRenewalInfo.setTaskInstanceId(taskItemExecuteRuntimeContext.getTaskItemInstanceId());
                taskItemExecuteRenewalInfo.setLastTaskRenewalSuccessTime(nowDateTime + taskItemExecuteRuntimeContext.getRenewalInterval());
                taskItemExecuteRenewalInfo.setLastTaskMaxAllowRunningTime(nowDateTime + taskItemExecuteRuntimeContext.getMaxAllowRunningTimeInterval());
                taskItemExecuteInfoService.renewal(taskItemExecuteRuntimeContext, taskItemExecuteRenewalInfo);
                return;
            }
            if (nowDateTime - lastTaskSelfReportTime > 1000 * 60 * 10) {
                taskItemExecuteRuntimeContext.needStop = true;
                taskItemExecuteRuntimeContext.needStopMessage = "即使任务线程你还活着也通知你不要执行了";

                return;
            }
            //2-10分钟内的不主动进行续期 因为状态检查是1分钟进行一次检查。要是任务活跃那么更新时间间隔差必然小于2分钟内
            return;


        }
    }

    protected void reportTaskItemExecuteRuntimeContext(TaskItemExecuteRuntimeContext taskItemExecuteRuntimeContext) {
        int successCount = 0;
        int errorCount = 0;
        int status = taskItemExecuteRuntimeContext.getStatus();
        if (status == Status.SUCCESS) {
            successCount = 1;
        } else {
            errorCount = 1;
        }
        // 执行次数加1
        String taskId = taskItemExecuteRuntimeContext.getTaskId();
        String executorId = taskItemExecuteRuntimeContext.getExecutorId();
        TaskStatistics.increaseTotalCountDelta(taskId, executorId);
        // 只要有出错和失败的分片，就认为是处理失败; 否则认为处理成功
        if (errorCount == 0) {
            TaskStatistics.incrementProcessSuccessCount(taskId, executorId, successCount);
        } else {
            TaskStatistics.increaseErrorCountDelta(taskId, executorId);
            TaskStatistics.incrementProcessFailureCount(taskId, executorId, errorCount);
        }
    }
}
